package com.company;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Main {

    public static void main(String[] args) {
	// write your code here
        test4();
    }


    /**
     * 获取反射的三种途径
     */
    public static void test(){
        //获取 类 的描述类Class的三种途径：
        //反射只是获取类的描述，同一个类的不同实例，获取的是同一个反射
        //（1）类名.class
        Class clazz = Student.class;        //泛型不写默认为Object
        Class<Student> clazz1 = Student.class;


        //(2)Class.forname静态方法获取，需要提供类的包路径名
        try {
            Class clazz2 = Class.forName("com.company.Student");            //包路径名

            System.out.println("clazz == clazz2:"+ (clazz == clazz2));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //(3)通过对象.getClass方法获取，需要事先new一个实例对象
        Student student = new Student(155,"男","sad",55,"af");
        Student student1 = new Student();
        Class clazz3 = student.getClass();
        Class clazz4 = student1.getClass();

        //三种方法都是获取一个对象的反射，属于同一个对象
        System.out.println("clazz4 == clazz3:"+ (clazz4 == clazz3));
        System.out.println("clazz1 == clazz3:"+ (clazz1 == clazz3));

    }

    /**
     * 通多获取的Class反射，来获取实例对象
     * 获得对象的实例对象
     */
    public static void test1(){
        //获取student的反射
        Class<Student> clazz = Student.class;


        try {
            //通过反射获取实例对象
            Student stu =  clazz.newInstance();      //等价于new,属性为默认值
            stu.skill();
            System.out.println(stu.toString());
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 反射工具类：Constructor工具类
     * 对构造函数进行操作
     */
    public static void test2(){
        //通过类.class获取类的反射
        Class<Student> clazz = Student.class;

        try {
            //获取类的构造方法              参数要跟类提供的构造方法匹配
            Constructor<Student> constructor =
                    clazz.getDeclaredConstructor(int.class,String.class,String.class,int.class,String.class);
            //通过构造方法获取类的实例对象                参数要跟获取的Constructor参数类型一致
            Student student = constructor.newInstance(15,"男","asd",90,"数据库");

            System.out.println(student.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 反射工具类：field工具类
     * 获取对象的属性
     */
    public static void test3(){

        Student student = new Student();
        Student student1 = new Student(155,"男","sad",55,"af");
        Class clazz = student1.getClass();

        try {
            //无法直接获取父类属性，只能获取当前类中显示定义的属性（包含private，protect，default，public）
            Field field = clazz.getDeclaredField("grade");
            //私有属性无法直接访问，必须设置为可见
            field.setAccessible(true);
            //修改指定类的属性
            field.set(student,150);


        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(student.toString());
        System.out.println(student1.toString());
    }

    /**
     * 反射工具类：Method工具类
     * 获取对象方法
     */
    public static void test4(){
        Student student = new Student();
        Class clazz = student.getClass();


        try {
            //返回反射对象的方法的反射        需要提供方法名，参数类型（没有则不写）
            Method method = clazz.getDeclaredMethod("skill");

            //执行方法的反射，需要提供对象，让该方法对象动态执行起来
            //如果有参数需要提供参数
            method.invoke(student);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
